#include "message.h"
#include "log.h"

#include<stdlib.h>

message_queue_t* message_queue_create(size_t max_size)
{
    // 申请队列内存
    message_queue_t* queue = (message_queue_t*)malloc(sizeof(message_queue_t));
    if (queue == NULL) {
        LOG_ERROR("create message queue failed");
        return NULL;
    }
    (void)memset(queue, 0, sizeof(message_queue_t));
    // 初始化锁
    int ret = pthread_mutex_init(&(queue->mutex), NULL);
    if (ret != 0) {
        LOG_ERROR("message queue init mutex failed");
        goto MESSAGE_QUEUE_CREATE_FAILED;
    }
    queue->head = NULL;
    queue->tail = NULL;
    queue->max_length = max_size;
    queue->current_length = 0;
    (void)gettimeofday(&queue->latest_update_time, NULL);
    return queue;

MESSAGE_QUEUE_CREATE_FAILED:
    message_queue_destroy(&queue);
    return NULL;
}

void message_queue_destroy(message_queue_t** queue)
{
    if (queue == NULL || *queue == NULL) {
        return;
    }
    pthread_mutex_lock(&((*queue)->mutex));
    message_t* message = (*queue)->head;
    while (message != NULL) {
        message_t* next = message->next;
        message_destroy(&message);
        message = next;
    }
    *queue = NULL;
    pthread_mutex_unlock(&((*queue)->mutex));
}

ret_t message_enqueue(message_queue_t* queue, message_t* message)
{
    // 加锁
    int ret = pthread_mutex_lock(&(queue->mutex));
    if (ret != 0) {
        LOG_ERROR("message queue lock failed");
        return PTHREAD_MUTEX_LOCK_FAILED;
    }
    // 判断队列是否已满
    if (queue->max_length <= 0) {
        LOG_ERROR("please check your queue max size seetings, which should be bigger than 0");
        return QUEUE_MAX_SIZE_INVALID;
    }
    // 如果队列是空，直接设置为头
    if (queue->head == NULL) {
        queue->head = message;
        queue->current_length = 1;
        gettimeofday(&queue->latest_update_time, NULL);
        pthread_mutex_unlock(&(queue->mutex));
        return RET_SUCCESS;
    }
    if (queue->current_length >= queue->max_length) {
        LOG_ERROR("message queue is full");
        pthread_mutex_unlock(&(queue->mutex));
        return QUEUE_IS_FULL;
    }
    // 否则将message放在队列尾部
    // 并根据优先级排队
    // 队列越靠近head的地方优先级越高，值越小
    
    queue->current_length++;
    gettimeofday(&queue->latest_update_time, NULL);
    // sort
    if (message->priority >= queue->tail->priority) {
        // 插入到队尾
        queue->tail->next = message;
        queue->tail = message;
    } else if (message->priority < queue->head->priority) {
        // 插入到头部
        message->next = queue->head;
        queue->head = message;
    } else {
        // 插入到中间
        message_t* tmp = queue->head;
        message_t* tmp_next = queue->head->next;
        while(message->priority >= tmp_next->priority) {
            tmp = tmp_next;
            tmp_next = tmp_next->next;
        }
        tmp->next = message;
        tmp->next->next = tmp_next;
    }
    pthread_mutex_unlock(&(queue->mutex));
    return RET_SUCCESS;
}

message_t* message_dequeue(message_queue_t* queue)
{
    if (queue == NULL) {
        return NULL;
    }
    pthread_mutex_lock(&(queue->mutex));
    if (queue->current_length == 0) {
        pthread_mutex_unlock(&(queue->mutex));
        return NULL;
    }
    message_t* message = queue->head;
    queue->head = queue->head->next;
    queue->current_length--;
    gettimeofday(&queue->latest_update_time, NULL);
    pthread_mutex_unlock(&(queue->mutex));
    return message;
}

message_t* message_create(const size_t data_bytes,
    const message_priority_t priority)
{
    message_t* message = (message_t*)malloc(sizeof(message_t) + data_bytes);
    if (message == NULL) {
        return NULL;
    }
    (void)memset(message, 0, sizeof(message_t) + data_bytes);
    message->priority = priority;
    message->data_bytes = data_bytes;
    gettimeofday(&message->time_created, NULL);
    message->next = NULL;
    return message;
}

void message_destroy(message_t** message)
{
    if (message == NULL || *message == NULL) {
        return;
    }
    free(*message);
    *message = NULL;
}